using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework.Graphics;
using System.IO;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Storage;
using Microsoft.Xna.Framework.GamerServices;
namespace StarlightEngine
{
    /// <summary>
    /// Engine is made of scenes. They house nodes and other features.
    /// </summary>
    public class Scene
    {

        Camera2D cam;
        public Camera2D Camera
        {
            get
            {
                return cam;
            }
            set
            {
                cam = value;
            }
        }
        Dictionary<string, Node> nodes;

        /// <summary>
        /// Takes the form of Name, Path
        /// </summary>
        public Dictionary<string, string> RequiredTextures = new Dictionary<string, string>();

        string date;
        string name;
        string creator;

        string lastAddedNode = "";

        public string addedAs = "";

        float zoomAmount = 1f;
        Vector2 camPos = Vector2.Zero;
        float rotationAmount = 0f;

        public float ZoomLevel
        {
            get { return zoomAmount; }
            set { zoomAmount = value; }
        }

        public float Rotation
        {
            get { return MathHelper.ToDegrees(rotationAmount); }
            set { rotationAmount = MathHelper.ToRadians(value); }
        }

        public Vector2 CameraPosition
        {
            get { return camPos; }
            set { camPos = value; }
        }
       

        /// <summary>
        /// Gets or sets the date.
        /// </summary>
        /// <value>The date.</value>
        public string Date
        {
            get { return date; }
            set { date = value; }
        }

        /// <summary>
        /// Gets or sets the name.
        /// </summary>
        /// <value>The name.</value>
        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        /// <summary>
        /// Gets or sets the name of the creators.
        /// </summary>
        /// <value>The name of the creators.</value>
        public string CreatorsName
        {
            get { return creator; }
            set { creator = value; }
        }

        public Node LastAddedNode
        {
            get { return nodes[lastAddedNode]; }
        }

        public Dictionary<string, Node> Nodes
        {
            get { return nodes; }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Scene"/> class.
        /// </summary>
        public Scene()
        {
            name = "Untitled";
            date = DateTime.Now.ToString();
            CreatorsName = "Developer <sample@zhde.isgreat>";
            nodes = new Dictionary<string, Node>();

            cam = new Camera2D(new Vector2(Engine.GraphicsDevice.Viewport.Width, Engine.GraphicsDevice.Viewport.Width));
        }

        // TODO : Turn into for loops.
        /// <summary>
        /// Draws this instance.
        /// </summary>
        public virtual void Draw()
        {
            foreach (KeyValuePair<string, Node> kp in nodes)
            {
                kp.Value.Draw();
            }
        }

        public void Zoom(float amount)
        {
            this.zoomAmount += amount;
        }

        public void Rotate(float degrees)
        {
            this.rotationAmount += MathHelper.ToRadians(degrees);
        }

        public void Move(Vector2 amount)
        {
            this.camPos += amount;
        }

        public void EditorUpdate()
        {
            cam.Position = this.CameraPosition;
            cam.Zoom = this.ZoomLevel;
            cam.Rotation = this.Rotation;
            foreach (KeyValuePair<string, Node> kp in nodes)
            {
                kp.Value.Update();
            }
        }

        /// <summary>
        /// Updates this instance.
        /// </summary>
        public virtual void Update()
        {
            if (Settings.Editor)
            {
                EditorUpdate();
                return;
            }
            else
            {
                cam.Position = this.camPos;
                cam.Zoom = ZoomLevel;
                cam.Rotation = this.rotationAmount;
                cam.Update();
                foreach (KeyValuePair<string, Node> kp in nodes)
                {
                    kp.Value.Update();
                }
            }
        }

        /// <summary>
        /// Clears this instance, removing all nodes.
        /// </summary>
        public void Clear()
        {
            nodes.Clear();
        }

        /// <summary>
        /// Adds the node.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="n">The node.</param>
        public void AddNode(string name, Node n)
        {
            if (!nodes.ContainsKey(name))
            {
                n.addedAs = name;
                n.inScene = addedAs;
                nodes.Add(name, n);
                lastAddedNode = name;
                return;
            }
            int tmp = 0;
            bool solved = false;
            string nm = name;
            while (solved == false)
            {
                if (!nodes.ContainsKey(nm))
                    solved = true;
                else
                {
                    nm = name;
                    nm += tmp;
                    tmp++;
                }
            }
            n.addedAs = nm;
            n.inScene = addedAs;
            nodes.Add(nm, n);
            lastAddedNode = nm;
        }

        public void RenameNode(string current, string newz)
        {
            Node tmp = nodes[current];
            nodes.Remove(current);
            nodes.Add(newz, tmp);
        }

        /// <summary>
        /// Saves to file.
        /// </summary>
        /// <param name="path">The path.</param>
        public void SaveToFile(string path)
        {
          /* Format
             * int totalnodes
             * int totalTextures
             * string[] textureNames
             * string[] texturePaths
             * string[] nodeNames
             * string[] textures
             * float[] scales
             * float[] rotation
             * int[] x
             * int[] y's
             * byte R
             * byte G
             * byte B
             * byte A
             * string name
             * string date
             * string creator
          */
            FileStream stream;
            BinaryWriter writer;
            stream = new FileStream(path, FileMode.Create);
            writer = new BinaryWriter(stream);

            //Assemble data.

            //Write the totalnodes.
            writer.Write((Int32)nodes.Count);
            writer.Write((Int32)RequiredTextures.Count);

            //Write texture names.

            foreach (string name in RequiredTextures.Keys)
            {
                writer.Write(name);
            }

            //Write texture paths.
            foreach (string paths in RequiredTextures.Values)
            {
                writer.Write(paths);
            }

            //Write all the names.
            foreach (string s in nodes.Keys)
            {
                writer.Write(s);
            }

            //Write all the texture names.
            foreach (Node n in nodes.Values)
            {
                writer.Write(n.Texture);
            }

            //Write all the texture scales.
            foreach (Node n in nodes.Values)
            {
                writer.Write((double)n.Scale);
            }

            //Write all the texture scales.
            foreach (Node n in nodes.Values)
            {
                writer.Write((double)n.Rotation);
            }

            //Write all the nodes X's
            foreach (Node n in nodes.Values)
            {
                writer.Write((Int32)n.Position.X);
            }

            //Write all the nodes Y's
            foreach (Node n in nodes.Values)
            {
                writer.Write((Int32)n.Position.Y);
            }

            //Write the colors
            //Red
            foreach (Node n in nodes.Values)
                writer.Write(n.DrawColor.R);
            //Green
            foreach (Node n in nodes.Values)
                writer.Write(n.DrawColor.G);
            //Blue
            foreach (Node n in nodes.Values)
                writer.Write(n.DrawColor.B);
            //Alpha
            foreach (Node n in nodes.Values)
                writer.Write(n.DrawColor.A);

            //Write name etc
            writer.Write(this.Name);
            writer.Write(this.Date);
            writer.Write(this.CreatorsName);



            //Close
            writer.Close();
            stream.Dispose();
        }

        /// <summary>
        /// Loads from file. Clears all previous nodes.
        /// </summary>
        /// <param name="path">The path.</param>
        public void LoadFromFile(string path)
        {
            //Clear old info.
            nodes.Clear();

            /* Format
              * int totalnodes
              * int totalTextures
              * string[] textureNames
              * string[] texturePaths
              * string[] nodeNames
              * string[] textures
              * float[] scales
              * float[] rotations.
              * int[] x
              * int[] y's
              * string name
              * string date
              * string creator
           */
            

            System.Diagnostics.Debug.WriteLine("About to open file...");
            string fix = StorageContainer.TitleLocation + "/" + path;
            FileStream f = File.OpenRead(fix);
            
            System.Diagnostics.Debug.WriteLine("OpenedFile!");
            
            BinaryReader r = new BinaryReader(f);
            

            //Get data.
            int total = r.ReadInt32();
            int textTot = r.ReadInt32();
            Dictionary<string, string> reqTexts = new Dictionary<string, string>();
            List<string> names, textures;
            names = new List<string>();
            textures = new List<string>();
            List<string> textureNames, texturePaths;

            //Read textures and their paths.

            //Read the names.
            textureNames = new List<string>();
            for (int i = 0; i < textTot; i++)
                textureNames.Add(r.ReadString());

            //Read  the paths
            texturePaths = new List<string>();
            for (int i = 0; i < textTot; i++)
                texturePaths.Add(r.ReadString());

            //Assemble the dictionary
            for (int i = 0; i < textTot; i++)
                reqTexts.Add(textureNames[i], texturePaths[i]);

            this.RequiredTextures = reqTexts;

            //Load all the textures if possible.
            foreach (KeyValuePair<string, string> data in this.RequiredTextures)
            {
                TextureManager.AddTexture(data.Key, data.Value);
            }

            //Read node names and their textures.
            for (int i = 0; i < total; i++)
                names.Add(r.ReadString());

            for (int i = 0; i < total; i++)
                textures.Add(r.ReadString());

            List<float> scale = new List<float>();
            for (int i = 0; i < total; i++)
                scale.Add((float)r.ReadDouble());
            List<float> rot = new List<float>();
            for (int i = 0; i < total; i++)
                rot.Add((float)r.ReadDouble());


            List<int> x, y;
            x = new List<int>();
            y = new List<int>();

            for (int i = 0; i < total; i++)
                x.Add(r.ReadInt32());

            for (int i = 0; i < total; i++)
                y.Add(r.ReadInt32());

            //Read the colors.
            List<Color> finalColor = new List<Color>();
            List<byte> red, green, blue, alpha;

            //Read reds.
            red = new List<byte>();
            for (int i = 0; i < total; i++)
                red.Add(r.ReadByte());

            //Read greens.
            green = new List<byte>();
            for (int i = 0; i < total; i++)
                green.Add(r.ReadByte());

            //Read blues.
            blue = new List<byte>();
            for (int i = 0; i < total; i++)
                blue.Add(r.ReadByte());

            //Read alphas.
            alpha = new List<byte>();
            for (int i = 0; i < total; i++)
                alpha.Add(r.ReadByte());

            //Construct colors.
            for (int i = 0; i < total; i++)
                finalColor.Add(new Color(red[i], green[i], blue[i], alpha[i]));
            

            string name, date, creator;
            name = r.ReadString();
            date = r.ReadString();
            creator = r.ReadString();

            this.Name = name;
            this.Date = date;
            this.CreatorsName = creator;

            //Assemble Vectors
            List<Vector2> vecs = new List<Vector2>();
            for (int i = 0; i < total; i++)
            {
                vecs.Add(new Vector2(x[i], y[i]));
            }

            //Make the nodes.
            for (int i = 0; i < total; i++)
            {
                string nName = names[i];
                Node tmp = new SpriteNode(textures[i]);
                tmp.Position = vecs[i];
                tmp.Scale = scale[i];
                tmp.Rotation = rot[i];
                tmp.DrawColor = finalColor[i];
                this.AddNode(nName, tmp);
            }

            r.Close();
            f.Dispose();
        }
    }
}